﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Threading;
using System.Collections.ObjectModel;
using System.ComponentModel;
using QuantumBitDesigns.Core;
using System.IO;
using System.Xml.Serialization;
using CrazyWorship1.ListenerService;

namespace CrazyWorship1
{
    public class AssetManager : INotifyPropertyChanged
    {
        public static string BaseFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "//CrazyWorship";
        public static string SongFolder = BaseFolder + "//Songs";
        public void SetClientManager(ClientManager clientManager)
        {
            _clientManager = clientManager;
        }
        ClientManager _clientManager;
        private ClientManager ClientManager
        {
            get
            {
                return _clientManager;
            }

        }
        public bool ContainsSongByName(string name)
        {
            
            foreach (SongInfo a in songList){
                if (a.Name == name)
                    return true;
            }
            
            return false;
        }
        public bool WaitForQueueToEmpty()
        {
            while (songQueue.Count > 0)
            {
                
            }
            return true;
        }
        public SongInfo GetSongByName(string name)
        {
            foreach (SongInfo a in songList)
            {
                if (a.Name == name)
                    return a;
            }
            throw new Exception("Song Not Found");
        }
        public AssetManager()
        {
            songList = new SongList(System.Windows.Threading.Dispatcher.CurrentDispatcher);
            songInfoQueue = new Queue<SongInfo>(); 
            songQueue = new Queue<Song>(); 
            LoadAllInfo();
            NotifyPropertyChanged("SongList");
           
            Thread thread = new Thread(new ThreadStart(mainloop));
            thread.Start();
         

        }
        private Queue<SongInfo> songInfoQueue;
        private static object songListLock = new object();
        private static object songQueueLock = new object();
        private static object songInfoQueueLock = new object();
        private void mainloop()
        {
            //SongList = new SongList();
            while (true)
            {
                if (reset)
                {
                   
                    songList.Clear();
                    reset = false;
                    Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Send, (Action)delegate { NotifyPropertyChanged("SongList"); });
                    donereset = true;
                }
                Song s;
                if (songQueue.Count != 0)
                {
                    SongInfo a = new SongInfo();
                    lock (songQueueLock)
                    {
                        s = songQueue.Dequeue();
                        DeleteSongInfo(s.Version, s.Id);
                        s.Save();
                        a = s.ToSongInfo();
                        a.Status = Status.NotSynced;
                    }
                    using (TimedLock timedLock = this.songList.AcquireLock())
                    {
                        songList.Add(a);
                    }
                    Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Send, (Action)delegate { NotifyPropertyChanged("SongList"); });
                }
                if (songInfoQueue.Count != 0)
                {
                    SongInfo a;
                    lock (songInfoQueueLock)
                    {
                         a= songInfoQueue.Dequeue();
                        DeleteSongInfo(a.Version, a.Id);
                        a.Status = Status.NotSynced;
                    }
                    using (TimedLock timedLock = this.songList.AcquireLock())
                    {
                        songList.Add(a);
                    }
                    Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Send, (Action)delegate { NotifyPropertyChanged("SongList"); });
                }
                if ((songQueue.Count == 0)&& (songInfoQueue.Count == 0))
                {
                    foreach (SongInfo si in songList)
                    {
                        Status status = Status.Synced;
                        if (_clientManager.ConnectedClients.Count != 0)
                        {
                            if (si.Tries / _clientManager.ConnectedClients.Count < 3)
                            {
                                foreach (BaseListenerClient cl in _clientManager.ConnectedClients)
                                {
                                    try
                                    {
                                        if (!cl.AssetsSongExists(si.Id, si.Version))
                                        {
                                            try
                                            {
                                                Song d = Song.LoadSong(si.SongFileName);
                                                //d.SongXml;
                                                    Stream stream=new MemoryStream();

                                                    using (StreamWriter writer = new StreamWriter(stream,Encoding.Unicode))
                                                    {
                                                        writer.AutoFlush = true;
                                                        writer.Write(d.SongXml);
                                                        stream.Position = 0;
                                                        
                                                        cl.AssetSongSend(si.Id, si.Name, si.Version, stream);
                                                    }
                                            }
                                            catch
                                            {
                                                si.Tries++;
                                                status = Status.NotSynced;
                                            }
                                        }
                                    }
                                    catch
                                    {
                                        status = Status.NotSynced;
                                        si.Tries++;
                                    }
                                }
                                si.Status = status;
                            }
                            else
                            {
                                si.Status = Status.GivenUp;
                            }
                        }
                        else
                        {
                            si.Status = Status.NotSynced;
                        }
                    }
                }
                Thread.Sleep(100);

            }
        }
        private bool reset = false;
        private bool donereset = false;
        public void Reset()
        {
            reset = true;
            while (!donereset) { }
            donereset = false;
        }
        public ObservableCollection<SongInfo> SongList
        {
            get
            {

                if (songList == null)
                {
                    return null;
                }

                return songList.ObservableCollection;
            }
        }

        private SongList songList;
        private Queue<Song> songQueue;
        private void DeleteSongInfo(Guid version, Guid id)
        {
            SongInfo r=null;
            foreach (SongInfo s in songList)
            {
                if ((s.Id == id) && (s.Version == version))
                {
                    r = s;
                }
            }
            if (r!=null)
                songList.Remove(r);

        }
        public void SaveSong(Song song)
        {
            //DeleteSongInfo(song.Version, song.Id);
            //song.Save();
            AddSong(song);

        }
        private void AddSong(Song song)
        {
            lock (songQueueLock)
            {
                songQueue.Enqueue(song);
            }
        }
        private void AddSongInfo(SongInfo song)
        {
     //       songInfo.Status = Status.NotSynced;
            songInfoQueue.Enqueue(song);
        }
        private void LoadAllInfo()
        {
            if (!Directory.Exists(SongFolder))
                Directory.CreateDirectory(SongFolder);
            foreach (string d in Directory.GetDirectories(SongFolder))
            {
                if (File.Exists(d + "//songinfo.xml"))
                {
                    SongInfo si = SongInfo.Load(d + "//songinfo.xml");
                    this.AddSongInfo(si);
                }
            }
            
        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }
        public void ClientsUnloadSong()
        {
            foreach (BaseListenerClient c in _clientManager.ConnectedClients)
            {
                c.SongUnload();
            }

        }
        public void ClientsLoadSong(Guid Id)
        {
            foreach (BaseListenerClient c in _clientManager.ConnectedClients)
            {
                c.SongLoad(Id);
            }
        }
    }
   
   
   
}
